/*
 * Copyright (c) 2001, 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 *    David Corbin  - added several status: BRANCHED_TO, REOPENED_FOR_ADD, OPENED_FOR_DELETE
 */
package net.sourceforge.perforce.core.internal.api;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;

import net.sourceforge.perforce.api.PerforceApiPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

/**
  * @version $Revision: 41 $
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  * @author  <a href="mailto:dcorbin@users.sourceforge.net">David Corbin</a>
  * 
  * TODO: Everything new with regular expressions ...
  */
class PerforceStatus
{
	// ---------------------------------------------------------------------------- Public Constants
	
	/** NO COMMENT */
	public static final IStatus OK = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1000, "", null);                  //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus FILES_UPTODATE = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1001, "FILE(S) UP-TO-DATE", null);//$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus OPENED_FOR_EDIT = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1002, "OPENED FOR EDIT", null);   //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus WAS_EDIT_REVERTED = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1003, "WAS EDIT REVERTED", null); //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus WAS_ADD_ABANDONED = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1004, "WAS ADD ABANDONED", null); //$NON-NLS-1$

	/** NO COMMENT */		
	public static final IStatus OPENED_FOR_ADD = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1005, "OPENED FOR ADD", null);    //$NON-NLS-1$

	/** NO COMMENT */		
	public static final IStatus CURRENTLY_OPENED_FOR_ADD = new Status(
		IStatus.OK, PerforceApiPlugin.ID, 1006, "CURRENTLY OPENED FOR ADD", null);     //$NON-NLS-1$

	/** NO COMMENT */		
	public static final IStatus CURRENTLY_OPENED_FOR_EDIT = new Status(
		IStatus.OK, PerforceApiPlugin.ID, 1007, "CURRENTLY OPENED FOR EDIT", null);    //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus UPDATING = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1008, "UPDATING", null);          //$NON-NLS-1$
		
	/** NO COMMENT */		
	public static final IStatus REOPENED_CHANGE = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1009, "REOPENED CHANGE", null);   //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus NOTHING_CHANGED = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1010, "NOTHING CHANGED", null);   //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus REFRESHING = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1011, "REFRESHING", null);        //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus ADDED_AS = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1012, "ADDED AS", null);          //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus DELETED_AS = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1013, "DELETED AS", null);        //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus BRANCHED_TO = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1014, "BRANCH/SYNC", null);       //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus REOPENED_FOR_ADD = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1015, "REOPENED FOR ADD", null);  //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus OPENED_FOR_DELETE  = 
		new Status(IStatus.OK, PerforceApiPlugin.ID, 1016, "OPENED FOR DELETE", null); //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus WAS_DELETE_REVERTED = new Status(
		IStatus.OK, PerforceApiPlugin.ID, 1017, "WAS DELETE REVERTED", null);          //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus NO_FILES_TO_RESOLVE = new Status(
		IStatus.OK, PerforceApiPlugin.ID, 1018, "NO FILE(S) TO RESOLVE", null);        //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus INFO = 
		new Status(IStatus.INFO, PerforceApiPlugin.ID, 2000, "", null);                //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus EMPTY_ASSUMING_TEXT = new Status(
		IStatus.INFO, PerforceApiPlugin.ID, 2001, "EMPTY ASSUMING TEXT", null);        //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus ALSO_OPENED_BY = 
		new Status(IStatus.INFO, PerforceApiPlugin.ID, 2002, "ALSO OPENED BY", null);  //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus MUST_SYNC_RESOLVE_BEFORE_SUBMITTING = new Status(IStatus.INFO, 
		PerforceApiPlugin.ID, 2003, "MUST SYNC/RESOLVE BEFORE SUBMITTING", null);      //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus LOCKED_BY = 
		new Status(IStatus.INFO, PerforceApiPlugin.ID, 2004, "LOCKED BY", null);       //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus IS_OPENED_AND_NOT_BEING_CHANGED = new Status(IStatus.INFO, 
		PerforceApiPlugin.ID, 2005, "IS OPENED AND NOT BEING CHANGED", null);          //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus NO_SUCH_FILES = 
		new Status(IStatus.INFO, PerforceApiPlugin.ID, 2006, "NO SUCH FILE(S)", null); //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus NO_FILES_RESOLVED = new Status(
		IStatus.INFO, PerforceApiPlugin.ID, 2007, "NO FILE(S) RESOLVED", null);        //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus FILES_NOT_OPENED_FOR_EDIT = new Status(IStatus.INFO, 
		PerforceApiPlugin.ID, 2009, "FILE(S) NOT OPENED FOR EDIT", null);              //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus FILES_NOT_IN_CLIENT_VIEW = new Status(IStatus.INFO,
		PerforceApiPlugin.ID, 2010, "FILE(S) NOT IN CLIENT VIEW", null);               //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus ERROR = 
		new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4000, "", null);               //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus MUST_RESOLVE_BEFORE_SUBMITTING = new Status(IStatus.ERROR, 
		PerforceApiPlugin.ID, 4001, "MUST RESOLVE BEFORE SUBMITTING", null);           //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus MUST_RESOLVE = 
		new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4002, "MUST RESOLVE", null);   //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus CANT_ADD_EXCLUSIVE_FILE_ALREADY_OPENED = new Status(IStatus.ERROR, 
		PerforceApiPlugin.ID, 4003, "CAN'T ADD EXCLUSIVE FILE ALREADY OPENED", null);  //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus ALREADY_LOCKED_BY =	new Status(IStatus.ERROR, 
		PerforceApiPlugin.ID, 4004, "ALREADY LOCKED BY", null);                        //$NON-NLS-1$
		
	/** NO COMMENT */
	public static final IStatus MUST_REFER_TO_CLIENT = new Status(IStatus.ERROR, 
		PerforceApiPlugin.ID, 4005, "MUST REFER TO CLIENT", null);                     //$NON-NLS-1$

	/** NO COMMENT */
	public static final IStatus FILES_NOT_ON_CLIENT = new Status(
		IStatus.ERROR, PerforceApiPlugin.ID, 4006, "FILE(S) NOT ON CLIENT", null);     //$NON-NLS-1$
		

	
	// --------------------------------------------------------------------------- Private Constants
		
	/** NO COMMENT */
	private static final String[] KNOWN_TOKENS = 
	{ 
		"FILE(S)",                                                                     //$NON-NLS-1$
	    "UP-TO-DATE",                                                                  //$NON-NLS-1$
		"WAS",                                                                         //$NON-NLS-1$
		"EDIT",                                                                        //$NON-NLS-1$
		"REVERTED",                                                                    //$NON-NLS-1$
		"OPENED",                                                                      //$NON-NLS-1$
		"FOR",                                                                         //$NON-NLS-1$
		"ADD",                                                                         //$NON-NLS-1$
		"ABANDONED",                                                                   //$NON-NLS-1$
		"EMPTY",                                                                       //$NON-NLS-1$
		"ASSUMING",                                                                    //$NON-NLS-1$
		"TEXT",                                                                        //$NON-NLS-1$
		"CURRENTLY",                                                                   //$NON-NLS-1$
		"ALSO",                                                                        //$NON-NLS-1$
		"BY",                                                                          //$NON-NLS-1$
		"MUST",                                                                        //$NON-NLS-1$
		"RESOLVE",                                                                     //$NON-NLS-1$
		"BEFORE",                                                                      //$NON-NLS-1$
		"SUBMITTING",                                                                  //$NON-NLS-1$
		"SYNC/RESOLVE",                                                                //$NON-NLS-1$
		"BRANCH/SYNC",                                                                 //$NON-NLS-1$
		"CAN'T",                                                                       //$NON-NLS-1$
		"EXCLUSIVE",                                                                   //$NON-NLS-1$
		"FILE",                                                                        //$NON-NLS-1$
		"ALREADY",                                                                     //$NON-NLS-1$
		"LOCKED",                                                                      //$NON-NLS-1$
		"UPDATING",                                                                    //$NON-NLS-1$
		"REOPENED",                                                                    //$NON-NLS-1$
		"CHANGE",                                                                      //$NON-NLS-1$
		"NOTHING",                                                                     //$NON-NLS-1$
		"CHANGED",                                                                     //$NON-NLS-1$
		"REFER",                                                                       //$NON-NLS-1$
		"TO",                                                                          //$NON-NLS-1$
		"CLIENT",                                                                      //$NON-NLS-1$
		"ADDED",                                                                       //$NON-NLS-1$
		"AS",                                                                          //$NON-NLS-1$
		"IS",                                                                          //$NON-NLS-1$
		"AND",                                                                         //$NON-NLS-1$
		"NOT",                                                                         //$NON-NLS-1$
		"BEING",                                                                       //$NON-NLS-1$
		"DELETED",                                                                     //$NON-NLS-1$
		"DELETE",                                                                      //$NON-NLS-1$
		"NO",                                                                          //$NON-NLS-1$
		"SUCH",                                                                        //$NON-NLS-1$
		"REFRESHING",                                                                  //$NON-NLS-1$
		"RESOLVED",                                                                    //$NON-NLS-1$
		"ON",                                                                          //$NON-NLS-1$
		"IN",                                                                          //$NON-NLS-1$
		"VIEW",                                                                        //$NON-NLS-1$
	};

	/** Dummy object (?!) */
	private static final PerforceStatus DUMMY = new PerforceStatus();

	// ------------------------------------------------------------------- Private Static Vatriables
	
	/** Will contain a sorted list of all known tokens. */ 
	private static List knownTokensList;
	/** Will contain a sorted status map. */
	private static Map statusMap;
	
	// -------------------------------------------------------------------- Static Initializer Block
	
	{
		knownTokensList = Arrays.asList(KNOWN_TOKENS);
		Collections.sort(knownTokensList);
		
		statusMap = new TreeMap();
		
		// IStatus.OK
		statusMap.put(FILES_UPTODATE.getMessage(), FILES_UPTODATE);
		statusMap.put(OPENED_FOR_EDIT.getMessage(), OPENED_FOR_EDIT);
		statusMap.put(WAS_EDIT_REVERTED.getMessage(), WAS_EDIT_REVERTED);
		statusMap.put(WAS_ADD_ABANDONED.getMessage(), WAS_ADD_ABANDONED);
		statusMap.put(OPENED_FOR_ADD.getMessage(), OPENED_FOR_ADD);
		statusMap.put(CURRENTLY_OPENED_FOR_ADD.getMessage(), CURRENTLY_OPENED_FOR_ADD);
		statusMap.put(CURRENTLY_OPENED_FOR_EDIT.getMessage(), CURRENTLY_OPENED_FOR_EDIT);
		statusMap.put(UPDATING.getMessage(), UPDATING);
		statusMap.put(REOPENED_CHANGE.getMessage(), REOPENED_CHANGE);
		statusMap.put(NOTHING_CHANGED.getMessage(), NOTHING_CHANGED);
		statusMap.put(REFRESHING.getMessage(), REFRESHING);
		statusMap.put(ADDED_AS.getMessage(), ADDED_AS);
		statusMap.put(DELETED_AS.getMessage(), DELETED_AS);
		statusMap.put(BRANCHED_TO.getMessage(), BRANCHED_TO);
		statusMap.put(REOPENED_FOR_ADD.getMessage(), REOPENED_FOR_ADD);
		statusMap.put(OPENED_FOR_DELETE.getMessage(), OPENED_FOR_DELETE);
		statusMap.put(WAS_DELETE_REVERTED.getMessage(), WAS_DELETE_REVERTED);
		statusMap.put(NO_FILES_TO_RESOLVE.getMessage(), NO_FILES_TO_RESOLVE);
				
		// IStatus.INFO
		statusMap.put(EMPTY_ASSUMING_TEXT.getMessage(), EMPTY_ASSUMING_TEXT);
		statusMap.put(ALSO_OPENED_BY.getMessage(), ALSO_OPENED_BY);
		statusMap.put(
			MUST_SYNC_RESOLVE_BEFORE_SUBMITTING.getMessage(), MUST_SYNC_RESOLVE_BEFORE_SUBMITTING);
		statusMap.put(LOCKED_BY.getMessage(), LOCKED_BY);
		statusMap.put(
			IS_OPENED_AND_NOT_BEING_CHANGED.getMessage(), IS_OPENED_AND_NOT_BEING_CHANGED);
		statusMap.put(NO_SUCH_FILES.getMessage(), NO_SUCH_FILES);
		statusMap.put(NO_FILES_RESOLVED.getMessage(), NO_FILES_RESOLVED);
		statusMap.put(FILES_NOT_OPENED_FOR_EDIT.getMessage(), FILES_NOT_OPENED_FOR_EDIT);
		statusMap.put(FILES_NOT_IN_CLIENT_VIEW.getMessage(), FILES_NOT_IN_CLIENT_VIEW);
		
		// IStatus.ERROR
		statusMap.put(
			MUST_RESOLVE_BEFORE_SUBMITTING.getMessage(), MUST_RESOLVE_BEFORE_SUBMITTING);
		statusMap.put(MUST_RESOLVE.getMessage(), MUST_RESOLVE);
		statusMap.put(CANT_ADD_EXCLUSIVE_FILE_ALREADY_OPENED.getMessage(), 
			CANT_ADD_EXCLUSIVE_FILE_ALREADY_OPENED);
		statusMap.put(ALREADY_LOCKED_BY.getMessage(), ALREADY_LOCKED_BY);
		statusMap.put(MUST_REFER_TO_CLIENT.getMessage(), MUST_REFER_TO_CLIENT);
		statusMap.put(FILES_NOT_ON_CLIENT.getMessage(), FILES_NOT_ON_CLIENT);
	}

	// --------------------------------------------------------------------------- Private Variables

	/** Stores the associated Status. */
	private IStatus status;	
	/** Stores the original message as provided by perforce. */
	private String originalMessage;

	// ----------------------------------------------------------------------- Public Static Methods
		
	/** Decodes the given perforce message into a status object.
	  *  
	  * @param perforceString the message provided by perforce.
	  * @param severity the severity.
	  * @return the decoded status object.
	  */
	public static IStatus decode(String perforceString, int severity)
	{
		int pos = perforceString.lastIndexOf(" - ");                                   //$NON-NLS-1$
		if (pos == -1)
		{
			return new Status(
				severity, OK.getPlugin(), severity, perforceString.trim(), OK.getException());
		}
	
		StringBuffer buffer = new StringBuffer();
		StringTokenizer tokenizer = 
			new StringTokenizer(perforceString.substring(pos + 3).toUpperCase(), " .,;\n");
		while (tokenizer.hasMoreTokens())
		{
			String token = tokenizer.nextToken();			
			int index = Collections.binarySearch(knownTokensList, token);

			if (index >= 0)
			{
				buffer.append(token);
			}

			if (buffer.length() > 0 && buffer.charAt(buffer.length() - 1) != ' ')
			{
				buffer.append(' ');	                                                   //$NON-NLS-1$
			}
		}

		IStatus result = null;
		
		String key = buffer.toString().trim();
		IStatus status = (IStatus) statusMap.get(key);
		if (status == null)
		{
			result = new Status(IStatus.ERROR, PerforceApiPlugin.ID, 999, 
				"Unknown result: " + perforceString + "<" + key + ">", null); 
		}
		else
		{
			result = new Status(status.getSeverity(), status.getPlugin(), status.getCode(), 
				perforceString.trim(), status.getException());		
		}
			
		return result;
	}			
}
